package com.yc.cloud.admin.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yc.cloud.admin.dto.request.HwMonitoringPointCreateReqDTO;
import com.yc.cloud.admin.dto.request.HwMonitoringPointQueryReqDTO;
import com.yc.cloud.admin.dto.request.HwMonitoringPointUpdateReqDTO;
import com.yc.cloud.admin.service.HwMonitoringPointService;
import com.yc.cloud.admin.service.HwRegionService;
import com.yc.cloud.admin.service.HwCameraService;
import com.yc.cloud.admin.vo.HwMonitoringPointVo;
import com.yc.cloud.admin.vo.HwCameraVo;
import com.yc.cloud.api.constants.SystemConfigConstants;
import com.yc.cloud.common.basic.exception.Asserts;
import com.yc.cloud.common.orm.CommonPage;
import com.yc.cloud.entity.HwMonitoringPoint;
import com.yc.cloud.entity.HwRegion;
import com.yc.cloud.entity.HwCamera;
import com.yc.cloud.mapper.HwMonitoringPointMapper;
import com.yc.cloud.mapper.HwRegionMapper;
import com.yc.cloud.mapper.HwCameraMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 监视点管理表 服务实现类
 * </p>
 *
 * @author Claude Code
 * @since 2025-09-29
 */
@Slf4j
@Service
public class HwMonitoringPointServiceImpl extends ServiceImpl<HwMonitoringPointMapper, HwMonitoringPoint> implements HwMonitoringPointService {

    @Resource
    private HwMonitoringPointMapper hwMonitoringPointMapper;

    @Resource
    private HwRegionMapper hwRegionMapper;

    @Resource
    private HwRegionService hwRegionService;

    @Resource
    private HwCameraMapper hwCameraMapper;

    @Resource
    private HwCameraService hwCameraService;

    @Override
    public Boolean create(HwMonitoringPointCreateReqDTO createReqDTO) {
        // 校验区域是否存在
        HwRegion region = hwRegionMapper.selectById(createReqDTO.getRegionId());
        if (region == null || region.getIsDeleted().equals(SystemConfigConstants.DELETED)) {
            throw new RuntimeException("所选区域不存在或已删除");
        }

        // 校验监视点编码唯一性
        if (StrUtil.isNotBlank(createReqDTO.getCode()) && existsByCode(createReqDTO.getCode(), null)) {
            throw new RuntimeException("监视点编码已存在");
        }

        HwMonitoringPoint monitoringPoint = new HwMonitoringPoint();
        BeanUtils.copyProperties(createReqDTO, monitoringPoint);
        monitoringPoint.setIsDeleted(SystemConfigConstants.NOT_DELETED);
        
        return this.save(monitoringPoint);
    }

    @Override
    public Boolean update(Long id, HwMonitoringPointUpdateReqDTO updateReqDTO) {
        HwMonitoringPoint existingPoint = this.getById(id);
        if (existingPoint == null || existingPoint.getIsDeleted().equals(SystemConfigConstants.DELETED)) {
            throw new RuntimeException("监视点不存在或已删除");
        }

        // 校验区域是否存在
        if (updateReqDTO.getRegionId() != null) {
            HwRegion region = hwRegionMapper.selectById(updateReqDTO.getRegionId());
            if (region == null || region.getIsDeleted().equals(SystemConfigConstants.DELETED)) {
                throw new RuntimeException("所选区域不存在或已删除");
            }
        }

        // 校验监视点编码唯一性
        if (StrUtil.isNotBlank(updateReqDTO.getCode()) && existsByCode(updateReqDTO.getCode(), id)) {
            throw new RuntimeException("监视点编码已存在");
        }

        BeanUtils.copyProperties(updateReqDTO, existingPoint);
        return this.updateById(existingPoint);
    }

    @Override
    public Boolean delete(Long id) {
        HwMonitoringPoint monitoringPoint = this.getById(id);
        if (monitoringPoint == null || monitoringPoint.getIsDeleted().equals(SystemConfigConstants.DELETED)) {
            throw new RuntimeException("监视点不存在或已删除");
        }

        // 逻辑删除
        monitoringPoint.setIsDeleted(SystemConfigConstants.DELETED);
        return this.updateById(monitoringPoint);
    }

    @Override
    public HwMonitoringPointVo getDetail(Long id) {
        HwMonitoringPoint monitoringPoint = this.getById(id);
        if (monitoringPoint == null || monitoringPoint.getIsDeleted().equals(SystemConfigConstants.DELETED)) {
            return null;
        }
        return convertToVo(monitoringPoint);
    }

    @Override
    public CommonPage<HwMonitoringPointVo> list(HwMonitoringPointQueryReqDTO queryReqDTO) {
        // 构建查询条件
        QueryWrapper<HwMonitoringPoint> query = buildQueryWrapper(queryReqDTO);
        
        // 分页查询
        IPage<HwMonitoringPoint> page = new Page<>(queryReqDTO.getPageNum(), queryReqDTO.getPageSize());
        IPage<HwMonitoringPoint> result = hwMonitoringPointMapper.selectPage(page, query);
        
        // 转换为VO
        List<HwMonitoringPointVo> voList = result.getRecords().stream()
                .map(this::convertToVo)
                .collect(Collectors.toList());
        
        // 手动构建CommonPage
        CommonPage<HwMonitoringPointVo> commonPage = new CommonPage<>();
        commonPage.setTotalPage((int) result.getPages());
        commonPage.setPageNum((int) result.getCurrent());
        commonPage.setPageSize((int) result.getSize());
        commonPage.setTotal(result.getTotal());
        commonPage.setList(voList);
        return commonPage;
    }

    @Override
    public List<HwMonitoringPointVo> listByRegionId(Long regionId) {
        List<HwMonitoringPoint> points = hwMonitoringPointMapper.selectByRegionId(regionId);
        return points.stream().map(this::convertToVo).collect(Collectors.toList());
    }

    @Override
    public List<HwMonitoringPointVo> listByRegionIds(List<Long> regionIds, boolean includeChildren) {
        List<Long> allRegionIds = new ArrayList<>(regionIds);
        
        if (includeChildren) {
            // 获取所有子区域
            for (Long regionId : regionIds) {
                List<Long> childRegionIds = hwRegionService.getChildrenIds(regionId);
                allRegionIds.addAll(childRegionIds);
            }
        }
        
        List<HwMonitoringPoint> points = hwMonitoringPointMapper.selectByRegionIds(allRegionIds);
        return points.stream().map(this::convertToVo).collect(Collectors.toList());
    }

    @Override
    public List<HwMonitoringPointVo> listByPointType(Integer pointType) {
        List<HwMonitoringPoint> points = hwMonitoringPointMapper.selectByPointType(pointType);
        return points.stream().map(this::convertToVo).collect(Collectors.toList());
    }

    @Override
    public List<HwMonitoringPointVo> listByImportanceLevel(Integer importanceLevel) {
        List<HwMonitoringPoint> points = hwMonitoringPointMapper.selectByImportanceLevel(importanceLevel);
        return points.stream().map(this::convertToVo).collect(Collectors.toList());
    }

    @Override
    public Boolean updateStatus(Long id, Integer status) {
        HwMonitoringPoint monitoringPoint = this.getById(id);
        if (monitoringPoint == null || monitoringPoint.getIsDeleted().equals(SystemConfigConstants.DELETED)) {
            throw new RuntimeException("监视点不存在或已删除");
        }
        
        monitoringPoint.setStatus(status);
        return this.updateById(monitoringPoint);
    }

    @Override
    public Boolean existsByCode(String code, Long excludeId) {
        return hwMonitoringPointMapper.existsByCode(code, excludeId);
    }

    @Override
    public Long countByRegionId(Long regionId) {
        return hwMonitoringPointMapper.countByRegionId(regionId);
    }

    @Override
    public List<HwMonitoringPointVo> listAllEnabled() {
        List<HwMonitoringPoint> points = hwMonitoringPointMapper.selectByStatus(SystemConfigConstants.STRATEGY_STATUS_ENABLED);
        return points.stream().map(this::convertToVo).collect(Collectors.toList());
    }

    @Override
    public HwMonitoringPointVo getByCode(String code) {
        HwMonitoringPoint monitoringPoint = hwMonitoringPointMapper.selectByCode(code);
        if (monitoringPoint == null) {
            return null;
        }
        return convertToVo(monitoringPoint);
    }

    /**
     * 构建查询条件
     */
    private QueryWrapper<HwMonitoringPoint> buildQueryWrapper(HwMonitoringPointQueryReqDTO queryReqDTO) {
        QueryWrapper<HwMonitoringPoint> query = new QueryWrapper<>();
        query.eq(HwMonitoringPoint.IsDeleted, SystemConfigConstants.NOT_DELETED);
        
        if (StrUtil.isNotBlank(queryReqDTO.getName())) {
            query.like(HwMonitoringPoint.Name, queryReqDTO.getName());
        }
        
        if (StrUtil.isNotBlank(queryReqDTO.getCode())) {
            query.like(HwMonitoringPoint.Code, queryReqDTO.getCode());
        }
        
        if (queryReqDTO.getRegionId() != null) {
            query.eq(HwMonitoringPoint.RegionId, queryReqDTO.getRegionId());
        }
        
        if (queryReqDTO.getPointType() != null) {
            query.eq(HwMonitoringPoint.PointType, queryReqDTO.getPointType());
        }
        
        if (queryReqDTO.getImportanceLevel() != null) {
            query.eq(HwMonitoringPoint.ImportanceLevel, queryReqDTO.getImportanceLevel());
        }
        
        if (queryReqDTO.getStatus() != null) {
            query.eq(HwMonitoringPoint.Status, queryReqDTO.getStatus());
        }
        
        // 排序：区域 > 重要程度 > 类型 > 名称
        query.orderByAsc(HwMonitoringPoint.RegionId, HwMonitoringPoint.ImportanceLevel, 
                         HwMonitoringPoint.PointType, HwMonitoringPoint.Name);
        
        return query;
    }

    /**
     * 转换为VO对象
     */
    private HwMonitoringPointVo convertToVo(HwMonitoringPoint monitoringPoint) {
        HwMonitoringPointVo vo = new HwMonitoringPointVo();
        BeanUtils.copyProperties(monitoringPoint, vo);
        
        // 获取区域名称
        if (monitoringPoint.getRegionId() != null) {
            HwRegion region = hwRegionMapper.selectById(monitoringPoint.getRegionId());
            if (region != null && !region.getIsDeleted().equals(SystemConfigConstants.DELETED)) {
                vo.setRegionName(region.getName());
            }
        }
        
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer bindCameras(Long monitoringPointId, List<Long> cameraIds) {
        // 1. 验证监视点是否存在
        HwMonitoringPoint monitoringPoint = hwMonitoringPointMapper.selectById(monitoringPointId);
        if (monitoringPoint == null || monitoringPoint.getIsDeleted().equals(SystemConfigConstants.DELETED)) {
            Asserts.fail("监视点不存在");
        }

        // 2. 验证相机是否存在
        if (cameraIds == null || cameraIds.isEmpty()) {
            log.warn("相机ID列表为空，无需绑定");
            return 0;
        }

        QueryWrapper<HwCamera> cameraQuery = new QueryWrapper<>();
        cameraQuery.in("id", cameraIds)
                   .eq(HwCamera.IsDeleted, SystemConfigConstants.NOT_DELETED);
        List<HwCamera> cameras = hwCameraMapper.selectList(cameraQuery);

        if (cameras.isEmpty()) {
            Asserts.fail("未找到有效的相机");
        }

        // 3. 先解绑该监视点原有的所有相机
        UpdateWrapper<HwCamera> unbindWrapper = new UpdateWrapper<>();
        unbindWrapper.eq(HwCamera.MonitoringPointId, monitoringPointId)
                    .set(HwCamera.MonitoringPointId, null);
        int unbindCount = hwCameraMapper.update(null, unbindWrapper);
        
        if (unbindCount > 0) {
            log.info("监视点 {} 解绑了 {} 个原有相机", monitoringPointId, unbindCount);
        }

        // 4. 批量绑定新的相机（会自动覆盖这些相机原来的监视点绑定）
        UpdateWrapper<HwCamera> bindWrapper = new UpdateWrapper<>();
        bindWrapper.in("id", cameraIds)
                  .set(HwCamera.MonitoringPointId, monitoringPointId);
        
        int updated = hwCameraMapper.update(null, bindWrapper);
        
        log.info("监视点 {} 批量绑定相机成功：绑定数量 {}", monitoringPointId, updated);
        
        return updated;
    }


    @Override
    public List<HwCameraVo> listBoundCameras(Long monitoringPointId) {
        // 1. 验证监视点是否存在
        HwMonitoringPoint monitoringPoint = hwMonitoringPointMapper.selectById(monitoringPointId);
        if (monitoringPoint == null || monitoringPoint.getIsDeleted().equals(SystemConfigConstants.DELETED)) {
            Asserts.fail("监视点不存在");
        }

        // 2. 查询绑定的相机
        QueryWrapper<HwCamera> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(HwCamera.MonitoringPointId, monitoringPointId)
                   .eq(HwCamera.IsDeleted, SystemConfigConstants.NOT_DELETED)
                   .orderByDesc("create_time");
        
        List<HwCamera> cameras = hwCameraMapper.selectList(queryWrapper);
        
        // 3. 转换为VO（复用HwCameraService的转换逻辑）
        return cameras.stream()
                      .map(camera -> hwCameraService.convertToVo(camera))
                      .collect(Collectors.toList());
    }

    @Override
    public List<HwCameraVo> listBindableCameras(Long monitoringPointId) {
        // 1. 验证监视点是否存在
        HwMonitoringPoint monitoringPoint = hwMonitoringPointMapper.selectById(monitoringPointId);
        if (monitoringPoint == null || monitoringPoint.getIsDeleted().equals(SystemConfigConstants.DELETED)) {
            Asserts.fail("监视点不存在");
        }

        // 2. 查询可绑定的相机：未绑定的 + 已绑定到当前监视点的
        QueryWrapper<HwCamera> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(HwCamera.IsDeleted, SystemConfigConstants.NOT_DELETED)
                   .and(wrapper -> wrapper
                       .isNull(HwCamera.MonitoringPointId)  // 未绑定任何监视点
                       .or()
                       .eq(HwCamera.MonitoringPointId, monitoringPointId)  // 或已绑定到当前监视点
                   )
                   .orderByAsc(
                       // 已绑定到当前监视点的排在前面（0），未绑定的排在后面（1）
                       "CASE WHEN monitoring_point_id = " + monitoringPointId + " THEN 0 ELSE 1 END"
                   )
                   .orderByDesc("create_time");
        
        List<HwCamera> cameras = hwCameraMapper.selectList(queryWrapper);
        
        // 3. 转换为VO
        return cameras.stream()
                      .map(camera -> hwCameraService.convertToVo(camera))
                      .collect(Collectors.toList());
    }

    @Override
    public Long countBoundCameras(Long monitoringPointId) {
        QueryWrapper<HwCamera> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(HwCamera.MonitoringPointId, monitoringPointId)
                   .eq(HwCamera.IsDeleted, SystemConfigConstants.NOT_DELETED);
        
        return hwCameraMapper.selectCount(queryWrapper);
    }
}